package com.aabte.threadpool.httpserver;

import com.aabte.threadpool.defaultthreadpool.DefaultThreadPool;
import com.aabte.threadpool.defaultthreadpool.ThreadPool;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;

/**
 * @author Daniel
 */
public class SimpleHttpServer {

    /**
     * 处理HttpRequest的线程池
     */
    static ThreadPool<HttpRequestHandler> threadPool = new DefaultThreadPool<>();

    /**
     * SimpleHttpServer的根路径
     */
    static String basePath;

    static ServerSocket serverSocket;

    static int port = 8080;

    public static void setPort(int port) {
        if (port > 0) {
            SimpleHttpServer.port = port;
        }
    }

    public static void setBasePath(String basePath) {
        if (basePath != null && new File(basePath).exists() && new File(basePath).isDirectory()) {
            SimpleHttpServer.basePath = basePath;
        }
    }

    /**
     * 启动SimpleHttpServer
     *
     * @throws IOException
     */
    public static void start() throws IOException {
        serverSocket = new ServerSocket(port);
        Socket socket = null;
        while ((socket = serverSocket.accept()) != null) {
            // 接收一个客户端socket，生成一个HttpRequestHandler，放入线程池执行
            threadPool.execute(new HttpRequestHandler(socket));
        }
        serverSocket.close();
    }

    static class HttpRequestHandler implements Runnable {

        private Socket socket;

        public HttpRequestHandler(Socket socket) {
            this.socket = socket;
        }

        @Override
        public void run() {
            String line = null;
            BufferedReader br = null;
            BufferedReader reader = null;
            OutputStream out = null;
            InputStream in = null;

            try {

                reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                String header = reader.readLine();
                String filePath = basePath + header.split(" ")[1];
                out = socket.getOutputStream();
                //如果请求资源的后缀为jpg或者ico，则读取资源并输出
                if (filePath.endsWith(".jpg") || filePath.endsWith(".ico")) {
                    in = new FileInputStream(filePath);
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    int i = 0;
                    while ((i = in.read()) != -1) {
                        baos.write(i);
                    }

                    byte[] array = baos.toByteArray();
                    out.write("HTTP/1.1 200 OK\n".getBytes(StandardCharsets.UTF_8));
                    out.write("Server: Molly\n".getBytes(StandardCharsets.UTF_8));
                    out.write("Content-Type: image/jpeg\n".getBytes(StandardCharsets.UTF_8));
                    out.write(("Content-Length: " + array.length + "\n").getBytes(StandardCharsets.UTF_8));
                    out.write("\n".getBytes(StandardCharsets.UTF_8));
                    out.write(array);
                } else {
                    br = new BufferedReader(new InputStreamReader(new FileInputStream(filePath)));
                    out = socket.getOutputStream();
                    out.write("HTTP/1.1 200 OK\n".getBytes(StandardCharsets.UTF_8));
                    out.write("Server: Molly\n".getBytes(StandardCharsets.UTF_8));
                    out.write("Content-Type: text/html;charset=UTF-8\n".getBytes(StandardCharsets.UTF_8));
                    out.write("\n".getBytes(StandardCharsets.UTF_8));
                    while ((line = br.readLine()) != null) {
                        out.write(line.getBytes(StandardCharsets.UTF_8));
                    }
                }
                out.flush();

            } catch (IOException e) {
                try {
                    out.write("HTTP/1.1 500\n".getBytes(StandardCharsets.UTF_8));
                    out.write("\n".getBytes(StandardCharsets.UTF_8));
                    out.flush();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
                e.printStackTrace();
            } finally {
                close(br, in, reader, out, socket);
            }
        }

        private void close(Closeable... closeables) {
            if (closeables != null) {
                for (Closeable closeable : closeables) {
                    if (null == closeable) {
                        continue;
                    }
                    try {
                        closeable.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}
